package cn.fanqinghong.ymcc.service.impl;

import cn.fanqinghong.ymcc.constants.CommonConstants;
import cn.fanqinghong.ymcc.constants.SmsCodeConstants;
import cn.fanqinghong.ymcc.constants.YmccError;
import cn.fanqinghong.ymcc.domain.MessageSms;
import cn.fanqinghong.ymcc.dto.RedisRegisterDto;
import cn.fanqinghong.ymcc.dto.SmsDto;
import cn.fanqinghong.ymcc.exception.GlobalException;
import cn.fanqinghong.ymcc.service.ICommonService;
import cn.fanqinghong.ymcc.service.IMessageSmsService;
import cn.fanqinghong.ymcc.util.AssertUtil;
import cn.fanqinghong.ymcc.util.StrUtils;
import cn.fanqinghong.ymcc.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * FAN
 * 2022/7/15  19:41
 */
@Service
@Slf4j
public class CommonServiceImpl implements ICommonService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private IMessageSmsService messageSmsService;
    @Autowired
    private SmsCodeConstants smsCodeConstants;
    /**
     * 获取图像验证码
     * @param key
     * @return
     */
    @Override
    public String imageCode(String key) {
        //判断输入的图像验证码是否为空
        if (!StringUtils.hasLength(key)) {
            throw new GlobalException(YmccError.COMMON_KEY_IS_NOT_EMPTY.getMessage()
                    , YmccError.COMMON_KEY_IS_NOT_EMPTY.getCode());
        }
        //        (每次都是直接生成新的，但是要覆盖前面的)
        String code = StrUtils.getComplexRandomString(4);//生成4位的验证码
//        。保存redis，设置过期时间  key是什么==前端请求给我传递的UUID
        redisTemplate.opsForValue().set(
                key,//前端传递的UUID
                code, //图片中的码儿
                smsCodeConstants.getTimeout(),//过期时间600m
                TimeUnit.SECONDS);//过期时间的单位
//        。使用2D引擎把code画成图
//        。把图使用Base64编码成字符串
//        。返回Base64编码的字符串
        return VerifyCodeUtils.verifyCode(100,38,code);//生成图片验证码
    }

    /**
     * 获取短信验证码
     * @param dto
     * @return
     */
    @Override
    public void smsCode(SmsDto dto) {
        //获得到图形验证码的key
        String imageCodeKey = dto.getImageCodeKey();
        //获得输入的手机号
        String phone = dto.getMobile();
        //输入的图形验证码的值
        String imageCodeValue = dto.getImageCode();
//        *
//         * 一：校验
//         *  1.空校验
        //手机号空验证
        AssertUtil.isNotNull(phone, YmccError.COMMON_PHONE_IS_EMPTY.getMessage());
        //手机号合法验证
        AssertUtil.isPhone(phone, YmccError.COMMON_PHONE_IS_EMPTY.getMessage());
        if (imageCodeKey.isEmpty() ||imageCodeValue.isEmpty()){
            throw new GlobalException("参数不能为空，请检查参数");
        }
//         *
//         *  2.校验图形验证码，根据imageCodeKey从redis获取图形验证码
        Object imageCodeTmp = redisTemplate.opsForValue().get(imageCodeKey);
//         *   。获取不到 图形验证码过期，重新获取
        if (imageCodeTmp == null){
            throw new GlobalException("验证码已经过期，请重新获取!!!");
        }
//         *   。获取到了，比对图形验证码是否正确
        if (!imageCodeTmp.toString().equalsIgnoreCase(imageCodeValue)){
            //         * 	  - 不正确，提示输入图形验证码错误
            throw new GlobalException(YmccError.COMMON_IMAGECODE_NOT_RIGHT.getMessage());
        }
        //         *  1.根据手机号拼接key，159，从redis获取曾今可能发送的短信验证码
        String key =  String.format(CommonConstants.REGISTER_PHONE_PREFIX,phone);
        sendSmsCode(key);
    }

    /**
     * 发送手机验证码
     * @param key
     */
    private void sendSmsCode(String key) {
//          获取手机号
        String phone = key.split(":")[1];
//         *   。没有注册过，往下走
//         * 二：短信验证码逻辑
//         *  1.根据手机号拼接key，register:159，从redis获取曾今可能发送的短信验证码
        //从redis中获取数据
        Object o = redisTemplate.opsForValue().get(key);
        String code = "";
        Date now = new Date();
        if (o != null){
//         *   1.1 获取到了
//         *     1.1.1 校验是否过了一分钟重发时间 value  9527:232468742341657213
            //从redis中获取到数据
            RedisRegisterDto registerDto = (RedisRegisterDto) o;
            if ((now.getTime() - registerDto.getTime())/1000 <= smsCodeConstants.getInterval()){
                throw new GlobalException(YmccError.COMMON_SERIOUS.getMessage(),
                        YmccError.NO_EMAIL_IS_EMPTY.getCode());
            }
//         * 	   。小于一分钟  哥屋恩
//         * 	   。大于一分中 （还没有到3分钟，验证码还有效），
//         * 	       使用还没过期的验证码，刷新过期时间
            code = registerDto.getCode();
        }else{
//         *   1.2 获取不到
//         *      1.2.1.生成新的短信验证码
            code = StrUtils.getRandomString(smsCodeConstants.getCodesize());
        }
//         *
//         *  3.存储redis 设置一个过期时间
//        String smsCodeValue = smsCode + ":" + now.getTime();
        RedisRegisterDto redisRegisterDto = new RedisRegisterDto(code, now.getTime());
        redisTemplate.opsForValue().set(
                key,//使用新生成的拼接的电话号码作为key
                redisRegisterDto,//拼接了时间戳的验证码
                smsCodeConstants.getTimeout(),//600秒过期时间
                TimeUnit.SECONDS
        );
//         *  4.发送短信
//         * @param dto
        //SmsUtils.sendSms(key,"亲，您的验证码是："+smsCode+"。请在3分钟内使用！！");
//        System.out.println(phone + "亲，您的验证码是："+smsCode+"。请在5分钟内使用！！");
        String message = String.format(smsCodeConstants.getSmsmessage(), code);
        log.info(message);
        saveSmsMessage(phone, code,message);
    }

    /**
     * 保存t_message_sms数据
     * @param phone
     * @param smsCode
     */
    private void saveSmsMessage(String phone, String smsCode,String message) {
        MessageSms messageSms = new MessageSms();
        messageSms.setContent(message);
        messageSms.setTitle(smsCodeConstants.getTitle());
        //获取请求体 request
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        messageSms.setIp(request.getRemoteAddr());
        messageSms.setMobile(phone);
        messageSmsService.insert(messageSms);
    }

}
